package test;

import com.alibaba.fastjson.*;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.thoughtworks.xstream.XStream;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.*;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.entity.HibernateUtil;
import org.hibernate.entity.UserEntity;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import redis.clients.jedis.Jedis;
import tk.mybatis.simple.mapper.ModelType2Mapper;
import tk.mybatis.simple.mapper.ModelTypeMapper;
import tk.mybatis.simple.model.ModelType;
import tk.mybatis.simple.service.MyTool;

import javax.sql.DataSource;
import java.beans.*;
import java.io.IOException;
import java.lang.reflect.*;
import java.sql.*;
import java.sql.Statement;
import java.util.*;
import java.util.Date;
import java.util.function.*;
import java.util.regex.*;
import java.util.stream.*;


public class TempClass {

    private static Logger logger = LoggerFactory.getLogger(TempClass.class);

    public static void main(String args[]) throws Exception {
        List<String> list = new ArrayList<String>() {
            {
                add("apple");
                add("banana");
                add("pear");
            }
        };
        for (String item : list) {
            System.out.println(item);
        }
    }

    private static void hibernateTest() {
        Session session = HibernateUtil.getSession();
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(UserEntity.class);
        Criteria criteria = detachedCriteria.getExecutableCriteria(session);
        List list = criteria.list();
        System.out.print(list);
    }

    //javabean事件定义调用及反射属性及事件信息
    private static void javaBeanTest() throws IntrospectionException {
        BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);
        Person person = new Person();
        person.addCustomListener(m -> System.out.print(m.getMessage()));
        person.fireEvent();
    }

    private static void dateTest() {
        Long currentTimeMillis = System.currentTimeMillis();
        Date current = new Date(currentTimeMillis);
        Long millis = current.getTime();
        Integer dayOfWeek = current.getDay();
        Date secondBaseDate = new Date(0);
        Date yearBaseDate = new Date(0, 0, 1, 8, 0, 0);


        Calendar calendar = Calendar.getInstance();
        Long millis2 = calendar.getTimeInMillis();
        Integer dayOfWeek2 = calendar.get(Calendar.DAY_OF_WEEK);
        Date current2 = calendar.getTime();
        calendar.setTimeInMillis(0);
        Date secondBaseDate2 = calendar.getTime();
        calendar.set(0, Calendar.JANUARY, 1);
        Date yearBaseDate2 = calendar.getTime();
        calendar.setTime(current);


        String dateString = DateFormatUtils.format(current, "yyyy/MM/dd E HH:mm:ss");

        DateTime dateTime = new DateTime(2018, 12, 1, 10, 5, 8);
        dateTime = DateTime.parse("2015-02-04 10:20:30", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        dateTime = dateTime.plusDays(1).minusHours(1);
        String dateTimeString = dateTime.toString("yyyy/MM/dd E HH:mm:ss");

    }


    //Local variable xxx defined in an enclosing scope must be final or effectively final
    //闭包的中的外部变量只能赋一次值
    private static void enclosingScopeTest(boolean input) {
        String[] a = {"1", "2"};
        String b;//如果b赋了值，就会报错
        if (input) {
            b = "2";
        } else {
            b = "3";
        }
        Boolean c = Arrays.stream(a).anyMatch(m -> m.equals(b));

        logger.info(c.toString());
    }

    //Mybatis-Spring代码方式配置
    private static void mybatisSpringJavaConfig() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(getDataSource());
        //Configuration configuration = new Configuration();
        //factoryBean.setConfiguration(configuration);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        factoryBean.setMapperLocations(resolver.getResources("classpath:test/mapper/*2*.xml"));
        factoryBean.setTypeAliasesPackage("tk.mybatis.simple.model");
        SqlSessionFactory factory = factoryBean.getObject();
        try (SqlSession session = factory.openSession()) {
            ModelType2Mapper mapper = session.getMapper(ModelType2Mapper.class);
            List<ModelType> list = mapper.selectAll2();
            System.out.println(list);
        }
    }

    //Mybatis代码方式配置
    private static void mybatisJavaConfig() {
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        Environment environment = new Environment("development", transactionFactory, getDataSource());
        Configuration configuration = new Configuration(environment);
        // 实体所在的包
        configuration.getTypeAliasRegistry().registerAliases("tk.mybatis.simple.model");
        //mybatis单独使用要求接口所在包名与xml所在文件夹一致，使用mybatis-spring则没有这个限制
        configuration.addMapper(ModelTypeMapper.class);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(configuration);
        try (SqlSession session = factory.openSession()) {
            ModelTypeMapper mapper = session.getMapper(ModelTypeMapper.class);
            List<ModelType> list = mapper.selectAll();
            System.out.println(list);
        }
    }

    //数据访问事务回滚
    private static void mybatisTransaction() {
        try (ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");) {
            MyTool myTool = context.getBean(MyTool.class);
            myTool.transactionTest();
        }
    }

    private static DataSource getDataSource() {
        // String driver = "com.mysql.jdbc.Driver";
        String driver = "org.sqlite.JDBC";
        // String url = "jdbc:mysql://localhost:3306/devtest";
        String url = "jdbc:sqlite::resource:ZXYY_CE_Arc_A_F1.db";
        // String username = "root";
        // String password = "123456";
        // DataSource dataSource = new PooledDataSource(driver, url, username,
        // password);
        PooledDataSource dataSource = new PooledDataSource();
        dataSource.setDriver(driver);
        dataSource.setUrl(url);
        return dataSource;
    }

    // 两种容器的创建，及设置父子关系
    private static void springParentContextTest() {
        try (ConfigurableApplicationContext context1 = new AnnotationConfigApplicationContext(AppConfig.class);
             ConfigurableApplicationContext context2 = new ClassPathXmlApplicationContext(
                     "applicationContext.xml");) {
            // 设置父容器
            context1.setParent(context2);
        }
    }

    //xml序列化
    private static void xmlOpTest() throws IOException {
        // File file = new File("XmlData.xml");
        // if (!file.exists()) {
        // file.createNewFile();
        // }

        JSONArray ja = new JSONArray().fluentAdd(new JSONObject().fluentPut("Name", "重大维修").fluentPut("ID", 2))
                .fluentAdd(new JSONObject().fluentPut("Name", "普通维修").fluentPut("ID", 2));
        Person person = new Person();
        JSONObject jo = new JSONObject().fluentPut("Array", ja).fluentPut("Object", person);
        System.out.println(XStream.class);
        XStream xStream = new XStream();
        xStream.processAnnotations(Person.class);
        xStream.aliasType("JSONObject", JSONObject.class);
        // TODO map转换不理想
        xStream.toXML(jo, System.out);
    }

    // 正则示例
    private static void regexTest() {
        boolean isMatch = Pattern.matches("a.+?e", "abcde");
        System.out.println(isMatch);

        Pattern pat = Pattern.compile("(ab){2}");
        Matcher matcher = pat.matcher("ababaceab333ababa_de");
        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }

    // 流操作收集器自定义实现测试
    private static void streamCollectTest() {
        Stream<Integer> stream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5});
        String a = stream.collect(new Collector<Integer, StringBuilder, String>() {
            @Override
            public Supplier<StringBuilder> supplier() {
                return StringBuilder::new;
            }

            @Override
            public BiConsumer<StringBuilder, Integer> accumulator() {
                return StringBuilder::append;
            }

            @Override
            public BinaryOperator<StringBuilder> combiner() {
                return StringBuilder::append;
            }

            @Override
            public Function<StringBuilder, String> finisher() {
                return StringBuilder::toString;
            }

            @Override
            public Set<Characteristics> characteristics() {
                return Collections.emptySet();
            }
        });
        System.out.println(a);
    }

    // java泛型的缺陷
    private static void genericTypeBug() {
        MyTestClass<?> x = new MyTestClass<Integer>();
        @SuppressWarnings("unchecked")
        MyTestClass<Integer> y = (MyTestClass<Integer>) x;
        y.op(123);

        List<Integer> list = new ArrayList<>();
        @SuppressWarnings({"unchecked", "rawtypes"})
        List<Object> list1 = (List) list;
        logger.info(Arrays.toString(list1.toArray(new Object[list1.size()])));
        List<?> a = Arrays.asList(1, 2, 3);
        @SuppressWarnings("unchecked")
        List<String> b = (List<String>) a;
        logger.info(Arrays.toString(b.toArray(new Object[b.size()])));
    }

    // java类似.net的可空类型
    private static void OptionalTest() {
        Person person = new Person();
        School school = new School();
        school.setName("山西大学管理系统");
        person.setSchool(school);
        Optional<Person> opp = Optional.of(person);
        String value = opp.map(Person::getSchool).map(School::getName).map(m -> m.substring(0, 3)).orElse("没值");
        System.out.println(value);
    }

    // 反射示例
    private static void reflectTest() throws ReflectiveOperationException {
        Class<?> clazz = Class.forName("test.Person");
        Field[] members = clazz.getFields();
        System.out.println(Arrays.toString(members));

        Constructor<?> c = clazz.getConstructor();
        Object o = c.newInstance();
        logger.debug(o.toString());
    }

    // json序列化反序列化示例
    private static void jsonTest() throws IOException {
        School school = new School();
        school.setName("学校");
        school.setAddress("太原 ");

        Person person = new Person();
        person.setAge(20);
        person.setAdult(true);
        person.setUPPER_PROP("大写属性");
        person.setSchool(school);

        Person person2 = new Person() {
            {
                setName("李四");
                setAdult(true);
                setSchool(school);
            }
        };

        List<Person> persons2 = new ArrayList<Person>() {
            {
                add(person2);
                add(person);
            }
        };
        List<Person> persons = new ArrayList<Person>();
        persons.add(person);
        persons.add(person2);

        //阿里巴巴的序列化工具是真正针对javabean的，会调get和set方法，大小写遵循javabean规范
        String jsonAli = JSON.toJSONString(persons, SerializerFeature.DisableCircularReferenceDetect);
        System.out.println(jsonAli);
        //jackson，会调get和set，如遇全大写加下划线，第一个单词全小写
        ObjectMapper mapper = new ObjectMapper();
        String jsonJackson = mapper.writeValueAsString(persons);
        System.out.println(jsonJackson);
        //gson，不调get和set，大小写完全与字段相同
        Gson gson = new Gson();
        String jsonGson = gson.toJson(persons);
        System.out.println(jsonGson);
        net.sf.json.JSON jsonO = net.sf.json.JSONSerializer.toJSON(persons);
        String jsonJsonLib = jsonO.toString();
        System.out.println(jsonJsonLib);

        String json = "{\"ageStr\":\"15\",\"adult\":true,\"UPPER_PROP\":\"大写\",\"school\":{\"name\":\"山西大学\"}}";
        //fastjson反序列化不区分大小写
        Person personAli = JSON.parseObject(json, Person.class);
        System.out.println(personAli);
        Person personAli2 = JSON.parseObject(json.replace("UPPER_PROP", "upper_prop"), Person.class);
        System.out.println(personAli2);
        //jackson反序列化大小写必须与序列化时规则一致，否则报异常
        Person personJackson = mapper.readValue(json.replace("UPPER_PROP", "upper_PROP"), Person.class);
        System.out.println(personJackson);
        //gson反序列化大小写与字段名不一致的一律忽略
        Person personGson = gson.fromJson(json, Person.class);
        System.out.println(personGson);
        Person personGson2 = gson.fromJson(json.replace("UPPER_PROP", "upper_prop"), Person.class);
        System.out.println(personGson2);


        String json1 = "{\"name\":\"abc\", \"elements\":[\"ccc\",\"ddd\"], \"objList\":[{\"count\":1},{\"count\":2}]}";
        JSONObject obj = JSON.parseObject(json1);
        System.out.println(obj);
    }

    // commons-lang包中的类测试
    private static void commonLangTest() {
        boolean b = ArrayUtils.contains(new int[]{1, 3, 5}, 5);
        System.out.println(b);
    }

    // jedis的阻塞队列取值
    private static void jedisBLPopTest() {
        try (Jedis jedis = new Jedis("192.168.1.87")) {
            jedis.auth("123456");
            jedis.select(4);

            for (int i = 0; i < 10; i++) {
                List<String> value = jedis.blpop(0, "myTest");
                for (String item : value) {
                    System.out.println(item);
                }
                System.out.println("---------------------------");
            }
        }
    }

    // jedis连接取值
    private static void jedisOp() {
        try (Jedis jedis = new Jedis("192.168.1.87")) {
            jedis.auth("123456");
            jedis.select(4);
            jedis.lpush("testx", "onlytest");
        }
    }

    // java中的linq
    private static void streamTest() {
        Integer[] a = {2, 3, 4, 5};
        Stream<Integer> stream = Arrays.stream(a);
        //Iterable<Integer> z = stream::iterator;
        // stream = stream.peek(System.out::println);
        Integer b = stream.mapToInt(m -> m).sum();
        System.out.println(b);

        List<String> list = Arrays.asList("12", "ab", "cd", "ef");
        List<String> list2 = Arrays.asList("ab", "cd");
        List<String> result = list.stream().filter(m -> !list2.contains(m)).collect(Collectors.toList());
        System.out.println(String.join(",", result));
    }

    // java连接Mysql的jdbc方式
    private static void connectMySql() throws ClassNotFoundException, SQLException {
        String dbDriver = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/test";
        Class.forName(dbDriver);
        try (Connection conn = DriverManager.getConnection(url, "root", "123");
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT * FROM book");) {
            System.out.println("bookid, name");
            while (rs.next()) {
                System.out.println(rs.getString("bookid") + ", " + rs.getString("name"));
            }
        }
    }
}

class MyTestClass<T extends Object> {
    public void op(T value) {
        System.out.println(value);
    }
}
